package com.example.socket.thread;

import com.alibaba.fastjson.JSONObject;
import com.example.pojo.CollarMsg;
import com.example.service.collar.CollarService;
import com.example.service.collar.RailingService;
import com.example.socket.properties.SocketProperties;
import com.example.socket.server.SocketServer;
import com.example.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author w
 */
@Slf4j
public class SocketThread extends Thread {

    private Socket socket;
    private String ip;
    private CollarService collarService;
    private ThreadPoolExecutor pool;
    private RailingService railingService;

    public SocketThread(Socket socket, CollarService collarService, SocketProperties properties,RailingService railingService) {
        this.collarService = collarService;
        this.socket = socket;
        this.railingService = railingService;
        this.ip = socket.getInetAddress().toString().split(":")[0].substring(1);
        this.pool= new ThreadPoolExecutor(
                properties.getPoolCore(),
                properties.getPoolMax(),
                properties.getPoolKeep(),
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(properties.getPoolQueueInit()),
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        //默认时间

        RedisUtil.setSleepTime(ip,1800000);
    }

    @Override
    public void run() {
        try{
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            while (true){
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
                bw.write("send");
                bw.flush();//将内容写到控制台
                log.info("send发送成功");

                String s1 = handle(inputStream);
                if (s1==null|| "".equals(s1)||s1.length()==0){
                    throw new SocketException("自然断开");
                }
                String json = s1.replaceAll("eof", "");
                log.info("客户端发过来的内容:" + json);
                log.info("全体连接状态："+ SocketServer.connectingSockets);
                //异常重连情况处理
                if (!SocketServer.connectingSockets.containsKey(ip)){
                    SocketServer.connectingSockets.put(ip,collarService.getBindedUserId(ip));
                }
                CollarMsg collarMsg = JSONObject.parseObject(json, CollarMsg.class);
                //创建子线程处理数据
                pool.execute(new SocketDataHandleThread(ip,collarMsg,railingService));

                Thread.sleep(RedisUtil.getSleepTime(ip));
            }

        }catch (SocketException e){
            SocketServer.connectingSockets.remove(ip);
            log.info(ip+"->连接已断开");
            log.info("目前连接数量："+SocketServer.connectingSockets.size());
        } catch (Exception e){
            e.printStackTrace();
            log.info("服务器运行异常："+e.getMessage());
        }

    }


    /**
     * 读取 InputStream 到 String字符串中
     */
    private String handle(InputStream inputStream) throws IOException {
            //<1>创建字节数组输出流，用来输出读取到的内容
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            //<2>创建缓存大小
            byte[] buffer = new byte[1024]; // 1KB
            //每次读取到内容的长度
            int len = -1;
            //<3>开始读取输入流中的内容
        //当等于-1说明没有数据可以读取了
            while ((len = inputStream.read(buffer)) != -1) {
                //把读取到的内容写到输出流中
                baos.write(buffer, 0, len);
                if(baos.toString().contains("eof")){
                    //判断结束标记
                    break;
                }
            }
            //<4> 把字节数组转换为字符串
            String content = baos.toString();
            //<5>关闭输入流和输出流
            baos.close();
            //<6>返回字符串结果
            return content;
    }

    /**
     * 计算两个日期相差的秒数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int calLastedTime(Date startDate, Date endDate) {
        long a = endDate.getTime();
        long b = startDate.getTime();
        return (int) ((a - b));
    }
}
